﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ZQNB.Common
{
    public class MyTreeHelper
    {
        private static object _lock = new object();

        #region 递归计算ID列表

        /// <summary>
        /// 从一个关系型结构数据中查找一棵树的子树，并返回ID的集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable">代表树的关系型结构数据的集合</param>
        /// <param name="getId"></param>
        /// <param name="getParentId"></param>
        /// <param name="idToSearch">子树的ID</param>
        /// <param name="includeSelfId">是否包含自身</param>
        /// <returns></returns>
        public static List<string> FindTheChildIds<T>(IEnumerable<T> enumerable, Func<T, string> getId, Func<T, string> getParentId, string idToSearch, bool includeSelfId = false)
        {
            lock (_lock)
            {
                List<string> resultList = new List<string>();
                MyTree<T> tree = MakeTree<T>(enumerable, getId, getParentId);

                MyTree<T> childTree = FindTheChildTree(tree, idToSearch);
                if (childTree != null)
                {
                    if (includeSelfId)
                    {
                        resultList.Add(childTree.Pk);
                    }
                    RecursivePrepareChild(resultList, childTree);
                }
                return resultList;
            }
        }

        /// <summary>
        /// 查树的子树
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="idToSearch"></param>
        /// <returns></returns>
        public static MyTree<T> FindTheChildTree<T>(MyTree<T> tree, string idToSearch)
        {
            //如果不传入参数，搜索返回整个树
            if (string.IsNullOrEmpty(idToSearch))
            {
                return tree;
            }

            //是否是当前的树
            if (idToSearch.Equals(tree.Pk, StringComparison.InvariantCultureIgnoreCase))
            {
                return tree;
            }

            //如果不是当前的树，递归向下查找
            if (tree.Children != null && tree.Children.Count > 0)
            {
                foreach (var item in tree.Children)
                {
                    return FindTheChildTree(item, idToSearch);
                }
            }

            //没有找到
            return null;
        }

        /// <summary>
        /// 递归查找孩子的ID的递归逻辑
        /// </summary>
        /// <param name="list"></param>
        /// <param name="tree"></param>
        private static void RecursivePrepareChild<T>(List<string> list, MyTree<T> tree)
        {
            if (tree.Children != null && tree.Children.Count > 0)
            {
                foreach (var item in tree.Children)
                {
                    list.Add(item.Pk);
                    RecursivePrepareChild(list, item);
                }
            }
            else
            {
                //叶子节点没有孩子
                return;
            }
        }

        #endregion

        #region 递归计算树模型

        /// <summary>
        ///转换成唯一的树根，内部包含了所有的子节点 
        ///要求输入的集合必须有唯一的根
        ///判断条件是父Id和自己Id相等，或者父Id是空
        ///如果找不到唯一，或者找到了多个，则抛出异常
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static MyTree<T> MakeTreeRoot<T>(IEnumerable<MyTree<T>> list)
        {
            lock (_lock)
            {
                MyTree<T> rootNode = null;
                if (list == null || list.Count() == 0)
                {
                    return null;
                }
                else
                {
                    //要求输入的集合必须有唯一的根
                    //判断条件是父Id和自己Id相等，或者父Id是空
                    //如果找不到唯一，或者找到了多个，则抛出异常
                    rootNode = list
                        .Where(m => m.ParentPk == m.Pk || string.IsNullOrEmpty(m.ParentPk)).Single();
                    PrepareChild(list, rootNode);
                    return rootNode;
                }
            }
        }

        public static MyTree<T> MakeTree<T>(IEnumerable<T> enumerable, Func<T, string> getId, Func<T, string> getParentId)
        {
            lock (_lock)
            {
                List<MyTree<T>> list = Convert<T>(enumerable, getId, getParentId);
                MyTree<T> rootNode = null;
                if (list == null || list.Count() == 0)
                {
                    return null;
                }
                else
                {
                    //要求输入的集合必须有唯一的根
                    //判断条件是父Id和自己Id相等，或者父Id是空
                    //如果找不到唯一，或者找到了多个，则抛出异常
                    rootNode = list
                        .Where(m => m.ParentPk == m.Pk || string.IsNullOrEmpty(m.ParentPk)).Single();
                    PrepareChild(list, rootNode);
                    return rootNode;
                }
            }
        }

        /// <summary>
        /// 递归绑定孩子节点
        /// </summary>
        /// <param name="list"></param>
        /// <param name="node"></param>
        private static void PrepareChild<T>(IEnumerable<MyTree<T>> list, MyTree<T> node)
        {
            IEnumerable<MyTree<T>> childs = list
               .Where(m => m.ParentPk == node.Pk && m.ParentPk != m.Pk);

            if (childs != null && childs.Count() > 0)
            {
                foreach (var item in childs)
                {
                    //item.Parent = node;
                    node.Children.Add(item);
                    PrepareChild(list, item);
                }
            }
            else
            {
                //叶子节点没有孩子
                return;
            }
        }

        #endregion

        private static List<MyTree<T>> Convert<T>(IEnumerable<T> enumerable, Func<T, string> getId, Func<T, string> getParentId)
        {
            List<MyTree<T>> list = new List<MyTree<T>>();
            if (enumerable == null || enumerable.Count() == 0)
            {
                return list;
            }

            foreach (var item in enumerable)
            {
                string id = getId.Invoke(item);
                string pid = getParentId.Invoke(item);
                MyTree<T> node = new MyTree<T>(id, pid, item);
                list.Add(node);
            }
            return list;
        }

        //Action<MenuTreeNode, MenuTreeNode> bindSelfAndParentAction = (self, parent) => parent.AddChild(self);
        //Func<Menu, MenuTreeNode> convertFunc = ConvertMenuToTreeNode;
        //MenuTreeNode treeNode = MyTreeHelper.MakeCustomTree(tree, convertFunc, bindSelfAndParentAction);
        //自定义转换
        public static T MakeCustomTree<TFrom, T>(MyTree<TFrom> myTree, Func<TFrom, T> convertFunc, Action<T, T> bindSelfAndParentAction)
        {
            T customTree = ConvertMyTreeToTreeNode(myTree, convertFunc, bindSelfAndParentAction);
            return customTree;
        }
        private static T ConvertMyTreeToTreeNode<TFrom, T>(MyTree<TFrom> myTree, Func<TFrom, T> convertFunc, Action<T, T> bindSelfAndParentAction)
        {
            T treeNode = convertFunc.Invoke(myTree.Value);
            foreach (var child in myTree.Children)
            {
                T childNode = ConvertMyTreeToTreeNode(child, convertFunc, bindSelfAndParentAction);
                bindSelfAndParentAction.Invoke(childNode, treeNode);
            }
            return treeNode;
        }

    }

    public class MyTree<T>
    {
        public MyTree()
        {
            Children = new List<MyTree<T>>();
        }

        public string Pk { get; set; }
        public string ParentPk { get; set; }

        public T Value { get; set; }
        public MyTree<T> Parent { get; set; }
        public List<MyTree<T>> Children { get; set; }

        public MyTree(string pk, string parentPk, T o)
        {
            Children = new List<MyTree<T>>();
            this.Pk = pk;
            this.ParentPk = parentPk;
            this.Value = o;
        }
    }
}
